package com.yochi.pictureseditor.factories;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.yochi.pictureseditor.constants.Constants;
import com.yochi.pictureseditor.images.Image;
import com.yochi.pictureseditor.images.ImageImpl;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;

public class ImageFactory {

	private static final String TAG = "ImageAndroidFactory";

	///////////////////////////
	// PUBLIC : CREATE IMAGE //
	///////////////////////////

	/** Convert Image object to Android Bitmap object */
	public static Image bitmapToImage(Bitmap bitmap) {
		Log.d(TAG, "convert bitmap to image");
		return convert(bitmap);
	}

	/** Convert Android Bitmap object to Image object */
	public static Bitmap imageToBitmap(Image image) {
		Log.d(TAG, "convert image to bitmap");
		return convert(image);
	}

	///////////////////////////
	// PUBLIC : RESIZE IMAGE //
	///////////////////////////

	/** return an Image object from another Image object scaled with the given factor */
	public Image resizeImage(Image image, double factor) {
		return resizeImage(imageToBitmap(image), factor);
	}

	/** return an Image object from a Bitmap image object scaled with the given factor */
	public static Image resizeImage(Bitmap bitmap, double factor) {
		int newWidth = (int) Math.sqrt((Math.pow(bitmap.getWidth(), 2))/factor);
		int newHeight = (int) Math.sqrt((Math.pow(bitmap.getHeight(), 2))/factor);
		Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, false);
		Image result = bitmapToImage(scaledBitmap);
//		scaledBitmap.recycle();
		return result;
	}
	
	/** return an Image object from a Bitmap image object */
	public static Image resizeImage(Bitmap imageBitmap) {
		if(Float.valueOf(imageBitmap.getWidth())/Constants.MAX_REQUIRED_SIZE > 1 || Float.valueOf(imageBitmap.getHeight())/Constants.MAX_REQUIRED_SIZE > 1){
			// compute rescale factor
			int newWidth = 0;
			int newHeight = 0;
			if(imageBitmap.getWidth()>imageBitmap.getHeight()) {
				newWidth = Constants.MAX_REQUIRED_SIZE;
				newHeight = (int) (newWidth*(Float.valueOf(imageBitmap.getHeight())/Float.valueOf(imageBitmap.getWidth())));
			} else {
				newHeight = Constants.MAX_REQUIRED_SIZE;
				newWidth = (int) (newHeight*(Float.valueOf(imageBitmap.getHeight())/Float.valueOf(imageBitmap.getWidth())));
			}
			double factor = Float.valueOf(imageBitmap.getWidth()*imageBitmap.getHeight()) / Float.valueOf(newWidth*newHeight);
			Log.i(TAG, "resizeImage.factor = "+factor);
			Image result = resizeImage(imageBitmap, factor);
//			imageBitmap.recycle();
			return result;
			
		} else {
			Image img = bitmapToImage(imageBitmap);
//			imageBitmap.recycle();
			return img;
		}
	}


	/////////////////////////
	// PUBLIC : SAVE IMAGE //
	/////////////////////////

	/** Save image on sdCard */
	public static String saveImage(Image image) {
		return saveImage(imageToBitmap(image));
	}

	/** Save image on sdCard */
	public static String saveImage(Image image, String path) {
		return saveImage(imageToBitmap(image), path);
	}

	/** Save bitmap on sdCard */
	public static String saveImage(Bitmap bitmap) {
		return saveImage(bitmap, null);
	}

	/** Save bitmap on sdCard 
	 * @return */
	public static String saveImage(final Bitmap bitmap, final String path) {
		if(bitmap == null) {
			return null;
		}
		ByteArrayOutputStream bytes = new ByteArrayOutputStream();
		bitmap.compress(Bitmap.CompressFormat.PNG, 80, bytes); 
		long now = System.currentTimeMillis();
		File fpath;
		String fileName;
		if(path == null) {
			fpath = new File(Constants.ROOT_PATH);
			fileName = Constants.ROOT_PATH+"saved"+now+".png";
		} else {
			fpath = new File(path);
			fileName = path + "stored"+now+".png";
		}
		if (!fpath.exists()) { fpath.mkdir(); }
		File file = new File(fileName);
		try { 
			file.createNewFile();
			FileOutputStream fo = new FileOutputStream(file);
			fo.write(bytes.toByteArray());
			fo.close();
		} catch (FileNotFoundException e) { 
			Log.e(TAG, String.valueOf(e)); 
			return null;
		} catch (IOException e) { 
			Log.e(TAG, String.valueOf(e)); 
			return null;
		}
		return fileName;
	}

	  /////////////
	 // PRIVATE //
	/////////////
	
	private static Image convert(Bitmap bitmap) {
		int largeur = bitmap.getWidth();
		int hauteur = bitmap.getHeight();
		int profondeur = 4;
		Image img = new ImageImpl(profondeur, largeur, hauteur);
		int pixelValue;
		for(int l=0; l<largeur; l++) {
			for(int h=0; h<hauteur; h++) {
				pixelValue = bitmap.getPixel(l, h);
				img.setPixel(0, l, h, (char) ((pixelValue & 0x00FF0000)>>16)); 
				img.setPixel(1, l, h, (char) ((pixelValue & 0x0000FF00)>>8)); 
				img.setPixel(2, l, h, (char) (pixelValue & 0x000000FF)); 
				img.setPixel(3, l, h, (char) ((pixelValue & 0xFF000000)>>24)); 
		}	}
		return img;
	}
	
	private static Bitmap convert(Image image) {
		if(image != null) {
			if(image.getProfondeur() == 4) {
				return Bitmap.createBitmap(fill4Layers(image), image.getLargeur(), image.getHauteur(), Bitmap.Config.ARGB_8888);
			}
			else if(image.getProfondeur() == 2) {
				return Bitmap.createBitmap(fill2Layers(image), image.getLargeur(), image.getHauteur(), Bitmap.Config.ARGB_8888);
			}
		} 
		return null;
	}
	
	private static int[] fill4Layers(Image image) {
		int largeur = image.getLargeur();
		int hauteur = image.getHauteur();
		int pixels[] = new int[largeur*hauteur];
		for(int l=0; l<largeur; l++) {
			for(int h=0; h<hauteur; h++) {
				pixels[l+h*largeur] = Color.argb(image.getPixel(3, l, h), image.getPixel(0, l, h), image.getPixel(1, l, h), image.getPixel(2, l, h));
			}
		}
		return pixels;
	}
	
	private static int[] fill2Layers(Image image) {
		int largeur = image.getLargeur();
		int hauteur = image.getHauteur();
		int pixels[] = new int[largeur*hauteur];
		for(int l=0; l<largeur; l++) {
			for(int h=0; h<hauteur; h++) {
				pixels[l+h*largeur] = Color.argb(image.getPixel(1, l, h), image.getPixel(0, l, h), image.getPixel(0, l, h), image.getPixel(0, l, h));
			}
		}
		return pixels;
	}

}
